package cn.jiedanba.itext5.gm.sign;

import cn.jiedanba.itext5.BCProvider;
import cn.jiedanba.itext5.gm.sign.signatureContainer.GMExternalSignatureContainer;
import cn.jiedanba.itext5.gm.sign.vo.GetPdfHash;
import cn.jiedanba.itext5.gm.sign.vo.GetPdfHashParamVo;
import cn.jiedanba.itext5.signatureContainer.MyExternalSignatureContainer;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.MakeSignature;
import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.jcajce.provider.digest.SM3;
import org.ofdrw.gm.ses.v4.SES_Header;
import org.ofdrw.gm.ses.v4.TBS_Sign;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Locale;

/**
 * 《GB/T 38540-2020 信息安全技术 安全电子签章密码技术规范》 签名
 */
public class ITextGM extends BCProvider {

    /**
     * 创建签名域，并获取摘要值
     *
     * @param param
     */
    public static GetPdfHash getPdfHash(GetPdfHashParamVo param) {
        try {
            ByteArrayOutputStream tmpos = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(param.getPdf());
            PdfStamper stamper = PdfStamper.createSignature(reader, tmpos, '\0', null, true);
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setVisibleSignature(
                    new Rectangle(param.getLlx(), param.getLly(), param.getUrx(), param.getUry()), param.getPageNo(),
                    appearance.getNewSigName());
            appearance.setSignatureGraphic(
                    Image.getInstance(param.getSeal().geteSealInfo().getPicture().getData().getOctets()));
            appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
            appearance.setRenderingMode(RenderingMode.GRAPHIC);
            appearance.setReason(param.getReason());
            appearance.setLocation(param.getLocation());
            GMExternalSignatureContainer signatureContainer = new GMExternalSignatureContainer();
            MakeSignature.signExternalContainer(appearance, signatureContainer, new Integer(40000 * 2 + 2));
            InputStream data = appearance.getRangeStream();
            MessageDigest externalDigest = new SM3.Digest();
            byte digest[] = DigestAlgorithms.digest(data, externalDigest);
            GetPdfHash returnVo = new GetPdfHash();
            returnVo.setDigesHash(digest);
            returnVo.setEmptySignaturePdf(tmpos.toByteArray());
            returnVo.setFieldName(appearance.getFieldName());

            // 组装国密电子签章 签名数据
            TBS_Sign toSign = new TBS_Sign().setVersion(SES_Header.V4).setEseal(param.getSeal())
                    .setTimeInfo(new ASN1GeneralizedTime(new Date(), Locale.CHINA)).setDataHash(digest)
                    .setPropertyInfo("Signature.xml");
            returnVo.setTBS_Sign(toSign);
            return returnVo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * @param signPdf   空签名域pdf文件
     * @param pcks7     签名数据
     * @param fieldName 签名域 标识
     * @return
     * @throws IOException
     * @throws DocumentException
     * @throws GeneralSecurityException
     */
    public static byte[] signDeferred(byte[] signPdf, byte[] pcks7, String fieldName)
            throws IOException, DocumentException, GeneralSecurityException {
        PdfReader reader = new PdfReader(signPdf);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        MakeSignature.signDeferred(reader, fieldName, baos, new MyExternalSignatureContainer(pcks7));
        return baos.toByteArray();
    }

}
